package org.hfy.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.hfy.dto.warehouse.InboundQueryDTO;
import org.hfy.dto.warehouse.OutboundCreateDTO;
import org.hfy.entity.Inbound;
import org.hfy.entity.Inventory;
import org.hfy.entity.Outbound;
import org.hfy.mapper.InboundMapper;
import org.hfy.mapper.OutboundMapper;
import org.hfy.service.InventoryService;
import org.hfy.service.OutboundService;
import org.hfy.exception.WarehouseException;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * 出库管理服务实现类
 * 
 * @author hfy
 * @version 1.0
 */
@Service
public class OutboundServiceImpl extends ServiceImpl<OutboundMapper, Outbound> implements OutboundService {

    @Autowired
    private InventoryService inventoryService;

    @Autowired
    private InboundMapper inboundMapper;

    @Override
    public IPage<Inventory> getAvailableStockPage(InboundQueryDTO queryDTO) {
        Page<Inventory> page = new Page<>(queryDTO.getCurrent(), queryDTO.getSize());
        return baseMapper.selectAvailableStockPage(page, queryDTO);
    }

    @Override
    public IPage<Outbound> getOutboundRecordsPage(InboundQueryDTO queryDTO) {
        Page<Outbound> page = new Page<>(queryDTO.getCurrent(), queryDTO.getSize());
        return baseMapper.selectOutboundRecordsPage(page, queryDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Outbound createOutbound(OutboundCreateDTO createDTO) {
        // 1. 验证库存充足性
        Inventory inventory = inventoryService.getByFactoryNo(createDTO.getFactoryNo());
        if (inventory == null) {
            throw new WarehouseException.DataNotFoundException("库存记录", createDTO.getFactoryNo());
        }
        
        if (inventory.getCurrentStockQuantity() < createDTO.getOutboundQuantity()) {
            throw new WarehouseException.InsufficientStockException(
                createDTO.getFactoryNo(), 
                inventory.getCurrentStockQuantity(), 
                createDTO.getOutboundQuantity());
        }

        // 2. 创建出库单
        Outbound outbound = new Outbound();
        BeanUtils.copyProperties(createDTO, outbound);
        
        // 生成出库单号
        outbound.setOutboundNo(generateOutboundNo());
        
        // 从库存记录复制相关信息
        copyInfoFromInventory(outbound, inventory);
        
        // 设置状态
        outbound.setStatus("已出库");
        outbound.setCreatedBy("system");
        
        // 保存出库单
        save(outbound);
        
        // 3. 更新库存记录
        inventoryService.updateStockQuantity(outbound.getFactoryNo(), null, outbound.getOutboundQuantity());
        
        return outbound;
    }

    @Override
    public Integer getTotalOutboundQuantityByInboundId(Long inboundId) {
        List<Outbound> outbounds = baseMapper.selectByInboundId(inboundId);
        return outbounds.stream()
                .mapToInt(Outbound::getOutboundQuantity)
                .sum();
    }

    /**
     * 生成出库单号
     * 格式：CK + yyyyMMddHHmmss + 3位序号
     */
    private String generateOutboundNo() {
        try {
            String dateTimeStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
            return "CK" + dateTimeStr + String.format("%03d", System.currentTimeMillis() % 1000);
        } catch (Exception e) {
            throw new WarehouseException.NumberGenerationException("出库单号", e);
        }
    }

    /**
     * 从库存记录复制信息到出库单
     */
    private void copyInfoFromInventory(Outbound outbound, Inventory inventory) {
        // 将inboundId设置为null，表示不关联特定入库单
        outbound.setInboundId(null);
        
        // 从库存记录复制相关信息
        if (outbound.getMaterialCode() == null || outbound.getMaterialCode().isEmpty()) {
            outbound.setMaterialCode(inventory.getMaterialCode());
        }
        if (outbound.getSalesperson() == null || outbound.getSalesperson().isEmpty()) {
            outbound.setSalesperson(inventory.getSalesperson());
        }
    }
} 